package com.fowo.api.datainterface.service.impl.implCore;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.fowo.api.common.query.SqlInjectionUtil;
import com.fowo.api.common.util.ContextHolder;
import com.fowo.api.datainterface.constants.DataTypeKind;
import com.fowo.api.datainterface.constants.RequestMethodKind;
import com.fowo.api.datainterface.entity.DatainterfaceLog;
import com.fowo.api.datainterface.model.DataContextModel;
import com.fowo.api.datainterface.service.serviceCore.BaseFromService;
import com.fowo.api.datainterface.service.serviceCore.BaseRetryService;
import com.fowo.api.datainterface.service.serviceCore.BaseToService;
import com.fowo.api.datainterface.util.Common;
import com.fowo.api.datainterface.util.JScriptUtil;
import com.fowo.api.datainterface.util.JsonUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.List;

/**
 * 数据接口 服务实现类
 */
@Service
@Slf4j
@DS("ds24")
@RequiredArgsConstructor
public class SqlServiceImpl implements BaseFromService, BaseToService, BaseRetryService {

    private final Common common;
    private final JScriptUtil jScriptUtil;
    // 引入 ID 生成算法
    private final IdentifierGenerator identifierGenerator = new DefaultIdentifierGenerator();



    private JdbcTemplate jdbcTemplate;

    public JdbcTemplate getJdbcTemplate() {
        return ObjectUtil.isNotEmpty(jdbcTemplate) ? jdbcTemplate : new JdbcTemplate(ContextHolder.getApplicationContext().getBean(DataSource.class));
    }

    private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

    public NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() {
        return ObjectUtil.isNotEmpty(namedParameterJdbcTemplate) ? namedParameterJdbcTemplate : new NamedParameterJdbcTemplate(ContextHolder.getApplicationContext().getBean(DataSource.class));
    }


    @Override
    public DataTypeKind getType() {
        return DataTypeKind.Sql;
    }

    @Override
    public Object invokeFrom(DataContextModel.DatainterfaceFromModel from, JSONObject currentParamsMap, JSONObject currentHeadersMap) {
        String sql = from.getQueryStatement();
        //防注入
        SqlInjectionUtil.filterContent(sql);
        Object res = null;
        log.info(StrUtil.format("执行的sql：{} 参数：{} "), sql, currentParamsMap);
        if (StrUtil.equalsIgnoreCase(RequestMethodKind.Insert.getValue(), from.getRequestMethod()) || StrUtil.equalsIgnoreCase(RequestMethodKind.Update.getValue(), from.getRequestMethod())) {
            try {
                if (!JsonUtil.containsKeysIgnoreCase(currentParamsMap, "id")) {
                    currentParamsMap.put("id", identifierGenerator.nextId(null));
                }
                //sqlManager.executeUpdate(sql, currentParamsMap);
                if (MapUtil.isEmpty(currentParamsMap)) {
                    res = getJdbcTemplate().update(sql);
                } else {
                    res = getNamedParameterJdbcTemplate().update(sql, currentParamsMap);
                }
            } catch (Exception ex) {
                throw new RuntimeException(StrUtil.format("{} SQL来源接口 {} ，执行 {} 批量操作 {} 发生异常 ", StrUtil.concat(true, from.getTaskCode()), from.getEnCode(), sql, StrUtil.subPre(JsonUtil.getObjectToString(currentParamsMap), 500)), ex);
            }
        } else if (StrUtil.equalsIgnoreCase(RequestMethodKind.Select.getValue(), from.getRequestMethod())) {
            try {
                //res = sqlManager.execute(sql, JSONObject.class, currentParamsMap);
                if (MapUtil.isEmpty(currentParamsMap)) {
                    res = getJdbcTemplate().queryForList(sql);
                } else {
                    res = getNamedParameterJdbcTemplate().queryForList(sql, currentParamsMap);
                }
            } catch (Exception ex) {
                throw ex;
            }
            try {
                JSONArray jsonToListMap = JsonUtil.getJsonToJsonArray(res);
                return jsonToListMap;
            } catch (Exception e) {
                throw new RuntimeException(StrUtil.concat(true, "拉取失败或无返回值：", StrUtil.subPre(JsonUtil.getObjectToString(res), 500)));
            }
        } else {
            Assert.isTrue(false, "{} 来源接口 {} ，指定的SQL类型 {} 错误！", StrUtil.concat(true, from.getTaskCode()), from.getEnCode(), from.getRequestMethod());
        }
        return jScriptUtil.callJsFrom(from.getDataProcessing(), res == null ? new ArrayList<>() : res, null, null);
    }


    /**
     * 执行SQLBatch
     *
     * @param to
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Object invokeTo(DataContextModel.DatainterfaceToModel to, JSONObject currentParamsMap, JSONObject currentHeadersMap) {
        String sql = to.getQueryStatement();
        //防注入
        SqlInjectionUtil.filterContent(sql);
        //拿到来源成功的数据执行dataProcessing赋给目标参数
        List<JSONObject> currentParamsArray = MapUtil.get(to.getMappingSuccessData(), to.getEnCode(), List.class, null);
        log.info(StrUtil.format("执行的sql：{} 参数：{} "), sql, currentParamsArray);
        int[] res = null;
        if (StrUtil.equalsIgnoreCase(RequestMethodKind.Insert.getValue(), to.getRequestMethod()) || StrUtil.equalsIgnoreCase(RequestMethodKind.Update.getValue(), to.getRequestMethod())) {
            try {
                for (JSONObject item : currentParamsArray) {
                    if (!JsonUtil.containsKeysIgnoreCase(item, "id")) {
                        item.put("id", identifierGenerator.nextId(null));
                    }
                }
                res = getNamedParameterJdbcTemplate().batchUpdate(sql, ArrayUtil.toArray(currentParamsArray, JSONObject.class));
//                res = sqlManager.executeBatchTemplateUpdate(sql, currentParamsArray);
            } catch (Exception ex) {
                //异常数据存储
                List<JSONObject> failDataList = CollUtil.newArrayList();
                for (Object data : currentParamsArray) {
                    JSONObject failData = new JSONObject();
                    String message = StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 1000);
                    failData.put(message, data);
                    failDataList.add(failData);
                }
                common.packFailData(to, failDataList);
                throw new RuntimeException(StrUtil.format("{} SQL目标接口 {} ，执行批量操作 {} 发生异常 {}", StrUtil.concat(true, to.getTaskCode()), to.getEnCode(), StrUtil.subPre(JsonUtil.getObjectToString(currentParamsArray), 500), ExceptionUtil.getRootCauseMessage(ex)));
            }
        } else {
            Assert.isTrue(false, "{} 目标接口 {} ，指定的SQL类型 {} 错误！", StrUtil.concat(true, to.getTaskCode()), to.getEnCode(), to.getRequestMethod());
        }
        return jScriptUtil.callJsFrom(to.getDataProcessing(), res == null ? new ArrayList<>() : res, null, null);
    }


    /**
     * 事务重试
     *
     * @param invoke
     * @param datainterfaceLog
     * @return
     */
    @Override
    public Boolean retryInvokeTo(DataContextModel.DatainterfaceInvokeModel invoke, DatainterfaceLog datainterfaceLog) {
        String sql = invoke.getQueryStatement();
        //防注入
        SqlInjectionUtil.filterContent(sql);
        JSONObject currentParams = JsonUtil.getJsonToBean(datainterfaceLog.getRequestContent(), JSONObject.class);
        log.info(StrUtil.format("执行的sql：{} 参数：{} "), sql, currentParams);
        if (StrUtil.equalsIgnoreCase(RequestMethodKind.Insert.getValue(), invoke.getRequestMethod()) || StrUtil.equalsIgnoreCase(RequestMethodKind.Update.getValue(), invoke.getRequestMethod())) {
            if (CollUtil.isEmpty(currentParams)) {
                return null;
            }
            try {
                if (!JsonUtil.containsKeysIgnoreCase(currentParams, "id")) {
                    currentParams.put("id", identifierGenerator.nextId(null));
                }
                //int[] res = sqlManager.executeBatchTemplateUpdate(sql, currentParamsArray);
                JSONObject[] append = ArrayUtil.append(new JSONObject[1], currentParams);
                int[] res = getNamedParameterJdbcTemplate().batchUpdate(sql, append);
                return true;
            } catch (Exception ex) {
                throw new RuntimeException(StrUtil.format("重试接口 {} ，执行 {} 批量操作 {} 发生异常 ", StrUtil.concat(true, invoke.getEnCode(), sql, StrUtil.subPre(JsonUtil.getObjectToString(currentParams), 500), ExceptionUtil.getRootCauseMessage(ex))));
            }
        } else {
            Assert.isTrue(false, "重试接口 {} ，指定的SQL类型 {} 错误！", invoke.getEnCode(), invoke.getRequestMethod());
        }
        return false;
    }


}
